#include "photoplugin.h"
#include <math.h>
#include <QtGui>
#include <Maestro/mcplugins.h>
#include <algorithm> // for random_shuffle
#include <ctime> // time used as random seed

using namespace std; // namespace for algorithms

const int limit=6;
const int showDuration=40;



PhotoPlugin::PhotoPlugin()
{
    srand((time(NULL)));
    imageHolder=new ImageDisplayer();
    //imageHolder->setScaledContents(true);
    imageHolder->setAlignment(Qt::AlignCenter);
    normalTime=3*1000;
    fastTime=1*1000;
    timer=new QTimer(this);
    connect(timer,SIGNAL(timeout()),this,SLOT(next()));
    state=0;
    effect=PhotoPlugin::Fade;
    transitionTime=1*100; // 1/10th of a second
    transitionTimer=new QTimer(this);
    connect(transitionTimer,SIGNAL(timeout()),this,SLOT(continueTransition()));
}

QString PhotoPlugin::getName() {
    return "Photos";
}

void PhotoPlugin::test() {

}

QIcon PhotoPlugin::getImage() {
    return QIcon(":/imgs/3F00_photosButton.png");
}

QStringList PhotoPlugin::getExtensions() {
    QStringList list=QStringList();
    list.append("jpg");
    list.append("png");
    return list;
}

QWidget * PhotoPlugin::getInterface() {
    return imageHolder;
}

QIcon PhotoPlugin::getIcon(MediaFile *mediaFile) {
    return QIcon(":/imgs/photos.png");
}

void PhotoPlugin::setMediaFile(MediaFile * mediaFile) {
    qDebug()<<"loading picture "<<mediaFile->fileLocation+"/"+mediaFile->shortName;
    try {
        QPixmap pixmap=QPixmap::fromImage(QImage(mediaFile->fileLocation+"/"+mediaFile->shortName));

        imageHolder->setPixmap(pixmap);
        imageHolder->show();
        qDebug() <<imageHolder->isVisible()<<" "<<imageHolder->size();

    } catch (char * error) {
        qDebug() <<error;
    }
}

void PhotoPlugin::play() { // what are the different states? enums (or comments) would come in handy
    switch(state) {
    case -1:
        disconnect(timer,SIGNAL(timeout()),this,SLOT(previous()));
        connect(timer,SIGNAL(timeout()),this,SLOT(next()));
        //timer->start(normalTime);
        transitionCount=-showDuration;
        transitionTimer->start(transitionTime);
        emit stateChanged(true);
        break;
    case 1:
        state=0;
        timer->stop();
        transitionTimer->stop();
        emit stateChanged(false);
        break;
    default:
        timer->stop();
        state=1;
        transitionCount=-showDuration;
        transitionTimer->start(transitionTime);
        emit stateChanged(true);
    }

}

void PhotoPlugin::fastForward() {
    if(state==-1) {
        disconnect(timer,SIGNAL(timeout()),this,SLOT(previous()));
        connect(timer,SIGNAL(timeout()),this,SLOT(next()));
    }
    state=2;
    timer->start(fastTime);
    transitionTimer->stop();
    emit stateChanged(true);
}

void PhotoPlugin::rewind() {
    state=-1;
    disconnect(timer,SIGNAL(timeout()),this,SLOT(next()));
    connect(timer,SIGNAL(timeout()),this,SLOT(previous()));
    timer->start(fastTime);
    transitionTimer->stop();
    emit stateChanged(true);
}

void PhotoPlugin::stop() {
    if(state==-1) {
        disconnect(timer,SIGNAL(timeout()),this,SLOT(previous()));
        connect(timer,SIGNAL(timeout()),this,SLOT(next()));
    }
    state=0;
    transitionTimer->stop();
    emit stateChanged(false);
}

void PhotoPlugin::next() {
    if(repeat == 2) // repeat one
    {
        // do nothing -- stay on the same image
    }
    else if(index+1<queue.size())
    {
        index++;
        try {
            QPixmap pixmap=QPixmap::fromImage(queue.at(index).scaled(imageHolder->width(),imageHolder->height(),Qt::KeepAspectRatio));
    
            imageHolder->setPixmap(pixmap);
            emit fileChanged(files->at(index)->shortName,index,queue.size());
    
        } catch (char * error) {
            qDebug() <<error;
        }
    }
    else if(index == queue.size()-1 && repeat == 1) // repeat all
    {
        index = 0;
        try {
            QPixmap pixmap=QPixmap::fromImage(queue.at(index).scaled(imageHolder->width(),imageHolder->height(),Qt::KeepAspectRatio));

            imageHolder->setPixmap(pixmap);
            qDebug() <<imageHolder->isVisible()<<" "<<imageHolder->size();
            emit fileChanged(files->at(index)->shortName,index,queue.size());

        } catch (char * error) {
            qDebug() <<error;
        }
    }
    else // (index == queue.size()-1)
    {
        timer->stop();
        transitionTimer->stop();
        emit stateChanged(false);
    }
}

void PhotoPlugin::previous() {
    transitionTimer->stop();
    if(repeat == 2) // repeat one
    {
        // do nothing -- stay on the same image
    }
    else if(index>0) {
        index--;
        try {
            QPixmap pixmap=QPixmap::fromImage(queue.at(index).scaled(imageHolder->width(),imageHolder->height(),Qt::KeepAspectRatio));
    
            imageHolder->setPixmap(pixmap);
            emit fileChanged(files->at(index)->shortName,index,queue.size());
    
        } catch (char * error) {
            qDebug() <<error;
        }
    }
    else if(index == 0 && repeat == 1) // repeat all
    {
        index = queue.size()-1;
        try {
            QPixmap pixmap=QPixmap::fromImage(queue.at(index).scaled(imageHolder->width(),imageHolder->height(),Qt::KeepAspectRatio));

            imageHolder->setPixmap(pixmap);
            qDebug() <<imageHolder->isVisible()<<" "<<imageHolder->size();
            emit fileChanged(files->at(index)->shortName,index,queue.size());

        } catch (char * error) {
            qDebug() <<error;
        }
    }
    else // (index == 0)
    {
        timer->stop();
        emit stateChanged(false);
    }
}

void PhotoPlugin::setShuffleState(bool shuffleState){
    this->shuffle=shuffleState;
    qDebug()<<"shuffle = " << shuffle;
    if(queue.isEmpty()) return; // shuffle has been clicked before the queue has been set. set the queue first
    if(shuffle) // shuffle the queue
    {
        while(queue.operator ==(tmpQueue)) // ensure that you don't shuffle to the original queue
            random_shuffle(queue.begin(), queue.end());
        qDebug()<<"Queue is shuffled";
    }
    else // sort the queue with help from the temp queue
    {
        for(int i = 0; i < queue.size(); ++i)
            queue.replace(i, tmpQueue[i]);
        qDebug()<<"Queue is sorted";
    }
}

/* Repeat One fades in and out of the same picture in slideshows.
   The transition ensures there's a difference between pause and repeat one,
   so that users know the difference between the two functions.

   The queue becomes circular when Repeat All is on.

   When Repeat is off during a slideshow, the last picture in the queue will fade out and nothing will fade in.
   This signifies the end of the slideshow.
*/
void PhotoPlugin::setRepeatState(int repeatState){
    this->repeat = repeatState;
    qDebug() << "repeat = " << repeat << " (0 = off, 1 = all, 2 = one)";
}

void calcTransitions(QList<QImage> * transitions, QImage baseImage, PhotoPlugin::TransitionEffect effect) {
    if(effect==PhotoPlugin::Fade) {
        for(int i=0; i<limit; i++) {
            QImage clone=baseImage.copy();
            int multiplier=100*pow(2,(i+1));
            for(int i=0; i<clone.height(); i++) {
                QRgb * pixels=(QRgb*)clone.scanLine(i);
                for(int j=0; j<clone.width(); j++) {
                    QColor color(pixels[j]);

                    pixels[j]=color.darker(multiplier).rgb();
                    //clone.setPixel(i,j,color.rgb());
                }
            }
           transitions->append(clone);
        }
    }
}

void PhotoPlugin::setMediaQueue(QList<MediaFile *> *files, int start) {
    if(index==start&&this->files==files) {
        return;
    }
    queue.clear();
    transitions.clear();
    bool errorEncountered=false;
    QString errorMessage="The following files failed to load as images: ";
    tmpQueue.clear();
    foreach(MediaFile * file, *files) { // append each file to queue
        QImage source;
        if(source.load(file->fileLocation+"/"+file->shortName)) { //FIXME Qimage::load crashes
            queue.append(source);
            QList<QImage> * currentTransitions=new QList<QImage>();
            transitions.append(currentTransitions);
            QFuture<void> future=QtConcurrent::run(calcTransitions,currentTransitions,source,PhotoPlugin::Fade);
            transitionLoaders.append(future);
            //future.waitForFinished();
            //calculateTransitions(&currentTransitions,source,PhotoPlugin::Fade);

        } else {
            if(errorEncountered) {
                errorMessage+=", ";
            }
            errorMessage += file->shortName;
            errorEncountered=true;

        }
        tmpQueue.append(source); // keep a copy for restoration purposes
    }
    if(errorEncountered) {
        emit error(errorMessage);
    }
    qDebug() <<"loading image";
    try {
        QPixmap pixmap=QPixmap::fromImage(queue.at(start).scaled(imageHolder->width(),imageHolder->height(),Qt::KeepAspectRatio));

        imageHolder->setPixmap(pixmap);
        this->files=files;
        index=start;
        emit fileChanged(files->at(index)->shortName,index,queue.size());
    } catch (char * error) {
        qDebug() <<error;
    }

    qDebug()<< "Media Queue has been set.";
    setShuffleState(shuffle);
}

void PhotoPlugin::setVolume(int) {
// left blank on purpose
}

void PhotoPlugin::continueTransition() {
    QImage clone;
    transitionCount++;
    if(transitionCount<=limit&&transitionCount>0) {
        //clone=queue.at(index).copy();
        QFuture<void> future=transitionLoaders.at(index);
        future.waitForFinished();
        if(effect==PhotoPlugin::None) {

        }
        else if(effect==PhotoPlugin::Fade) {
            /*int multiplier=100*pow(2,transitionCount*2);
            for(int i=0; i<clone.height(); i++) {
                QRgb * pixels=(QRgb*)clone.scanLine(i);
                for(int j=0; j<clone.width(); j++) {
                    QColor color(pixels[j]);

                    pixels[j]=color.darker(multiplier).rgb();
                    //clone.setPixel(i,j,color.rgb());
                }
            }*/
            qDebug()<<transitions.size();
            qDebug()<<transitions.at(index)->size();
            if(transitions.at(index)->size()==0) {
                qDebug()<<"aborting";
                state=0;
                timer->stop();
                transitionTimer->stop();
                emit stateChanged(false);
                return;

            }
            clone=transitions.at(index)->at(transitionCount-1);
        }
    }
    else if(transitionCount>2*limit) {
        transitionCount=0;
        if(repeat != 2) index++; // repeat one
        if(index==queue.size())
        {
            index = 0;
            if(repeat != 1) // if not repeat all, stop at end
            {
                state=0;
                timer->stop();
                transitionTimer->stop();
                emit stateChanged(false);
                return;
            }
        }
        clone=queue.at(index).copy();
        transitionCount=-showDuration; //wait on newly faded in image before continuing
        emit fileChanged(files->at(index)->shortName,index,queue.size());
    }
    else if(transitionCount>limit) { //halfway start transitioning to next
        int ind=index;
        if(repeat != 2) ind++; // repeat one
        if(ind==queue.size())
        {
            ind = 0;
            if(repeat != 1) // if not repeat all, stop at end
            {
                state=0;
                timer->stop();
                transitionTimer->stop();
                emit stateChanged(false);
                return;
            }
        }
        clone=queue.at(ind).copy(); // a modified version of this specifying, x,y,width and height could be used for panning and zooming

        if(effect==PhotoPlugin::None) {

        }
        else if(effect==PhotoPlugin::Fade) {
            qDebug()<<(2*limit-transitionCount);
            int ind=index;
            if(repeat != 2) ind++; // repeat one
            if(ind==queue.size())
            {
                ind = 0;
                if(repeat != 1) // if not repeat all, stop at end
                {
                    state=0;
                    timer->stop();
                    transitionTimer->stop();
                    emit stateChanged(false);
                    return;
                }
            }
            QFuture<void> future=transitionLoaders.at(ind);
            future.waitForFinished();
           // transitionLoaders.at(ind).waitForFinished();
            clone=transitions.at(ind)->at(2*limit-transitionCount);
            qDebug()<<"worked";
            //qDebug()<<"fading in";
            /*int multiplier=100*pow(2,(2*limit-transitionCount)*2);
            for(int i=0; i<clone.height(); i++) {
                QRgb * pixels=(QRgb*)clone.scanLine(i);
                for(int j=0; j<clone.width(); j++) {
                    QColor color(pixels[j]);
                    

                    pixels[j]=color.darker(multiplier).rgb();
                    //clone.setPixel(i,j,color.rgb());
                }
            }*/
        }
    } else {
        clone=queue.at(index).copy();
    }

    QPixmap pixmap=QPixmap::fromImage(clone.scaled(imageHolder->width(),imageHolder->height(),Qt::KeepAspectRatio));

    imageHolder->setPixmap(pixmap);

}

bool PhotoPlugin::setSlider(Phonon::SeekSlider *slider) {
    return false;
}

void PhotoPlugin::calculateTransitions(QList<QImage> * transitions, QImage baseImage, TransitionEffect effect) {
    if(effect==PhotoPlugin::Fade) {
        for(int i=0; i<limit; i++) {
            QImage clone=baseImage.copy();
            int multiplier=100*pow(2,(i+1)*2);
            for(int i=0; i<clone.height(); i++) {
                QRgb * pixels=(QRgb*)clone.scanLine(i);
                for(int j=0; j<clone.width(); j++) {
                    QColor color(pixels[j]);

                    pixels[j]=color.darker(multiplier).rgb();
                    //clone.setPixel(i,j,color.rgb());
                }
            }
           transitions->append(clone);
        }
    }
}

Q_EXPORT_PLUGIN2(bmc_videoplugin, PhotoPlugin)

